#include <cstdint>
#include <string>
#include <vector>

#include <include/core/SkFont.h>
#include <include/core/SkTypeface.h>
#include <hb.h>
#include <unicode/utf8.h>

namespace {
hb_blob_t *HbFaceReferenceTableSkTypeface(hb_face_t *face, hb_tag_t tag, void *context)
{
    SkTypeface* typeface = reinterpret_cast<SkTypeface*>(context);
    if (typeface == nullptr) {
        return nullptr;
    }

    const size_t tableSize = typeface->getTableSize(tag);
    if (tableSize == 0) {
        return nullptr;
    }

    void* buffer = malloc(tableSize);
    if (buffer == nullptr) {
        return nullptr;
    }

    size_t actualSize = typeface->getTableData(tag, 0, tableSize, buffer);
    if (tableSize != actualSize) {
        free(buffer);
        return nullptr;
    }

    return hb_blob_create(reinterpret_cast<char *>(buffer),
                          tableSize, HB_MEMORY_MODE_WRITABLE, buffer, free);
}
} // namespace

int main(int argc, char **argv)
{
    std::string str = "Hello World";
    if (argc > 1) {
        str = argv[1];
    }

    // 获取码点
    std::vector<uint32_t> codepoints;
    {
        const auto &slen = str.size();
        for (int i = 0; i < slen;) {
            uint32_t codepoint = 0;
            U8_NEXT(str.data(), i, slen, codepoint);
            codepoints.push_back(codepoint);
        }
    }

    // 塑型
    {
        constexpr int size = 16;

        SkFont sfont;
        const auto &stypeface = SkTypeface::MakeFromFile("out/DroidSansFallback.ttf");
        sfont.setTypeface(stypeface);
        sfont.setSize(size);

        double em = stypeface->getUnitsPerEm();

        const auto &hbuffer = hb_buffer_create();
        hb_buffer_add_codepoints(hbuffer, codepoints.data(), codepoints.size(), 0, -1);
        hb_buffer_set_direction(hbuffer, HB_DIRECTION_LTR);
        hb_buffer_set_script(hbuffer, HB_SCRIPT_LATIN);
        hb_buffer_set_language(hbuffer, hb_language_from_string("en", -1));
        const auto &hface = hb_face_create_for_tables(HbFaceReferenceTableSkTypeface, stypeface.get(), 0);
        const auto &hfont = hb_font_create(hface);
        hb_shape(hfont, hbuffer, nullptr, 0);
        uint32_t ng = 0u;
        auto hginfos = hb_buffer_get_glyph_infos(hbuffer, &ng);
        auto hgpositions = hb_buffer_get_glyph_positions(hbuffer, nullptr);

        for (uint32_t i = 0; i < ng; i++) {
            char u8str[8] = "'";
            int u8index = 1;
            bool error = false;
            U8_APPEND(u8str, u8index, sizeof(u8str), codepoints[i], error);
            u8str[u8index] = '\'';

            printf("  %02u: %-4s (char: 0x%02X, glyphid: 0x%04X, cluster: %2u) {%.3lf, %.3lf, %.2lf, %.2lf}\n",
                   i, u8str, u8str[0], hginfos[i].codepoint, hginfos[i].cluster,
                   size * hgpositions[i].x_advance / em, size * hgpositions[i].y_advance / em,
                   size * hgpositions[i].x_offset / em, size * hgpositions[i].y_offset / em);
        }
    }
    return 0;
}
